package torrent;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.*;
import library.QueryString;

public class Tracker extends Thread {

  Socket connectedClient = null;
  BufferedReader inFromClient = null;
  DataOutputStream outToClient = null;
  String query;
  Map<String, List<String>> map;

  public Tracker(Socket client) {
    connectedClient = client;
  }

  @Override
  public void run() {

    try {
      System.out.println("The Client "
              + connectedClient.getInetAddress() + ":" + connectedClient.getPort() + " is connected");

      inFromClient = new BufferedReader(new InputStreamReader(connectedClient.getInputStream()));
      outToClient = new DataOutputStream(connectedClient.getOutputStream());

      String requestString = URLDecoder.decode(inFromClient.readLine(), "UTF-8");
      query = requestString;
      map = getUrlParameters(query);
      String headerLine = requestString;
      StringTokenizer tokenizer = new StringTokenizer(headerLine);
      String httpMethod = tokenizer.nextToken();
      String httpQueryString = tokenizer.nextToken();

      StringBuilder responseBuffer = new StringBuilder();
      responseBuffer.append("<b> This is the HTTP Server Home Page.... </b><BR>");
      responseBuffer.append("The HTTP Client request is ....<BR>");

      System.out.println("The HTTP request string is ....");
      while (inFromClient.ready()) {
        // Read the HTTP complete HTTP Query
        responseBuffer.append(requestString).append("<BR>");
        System.out.println(requestString);
        requestString = inFromClient.readLine();
      }

      if (httpMethod.equals("GET")) {
        if (httpQueryString.equals("/")) {
          // The default home page
          sendResponse(200, responseBuffer.toString(), false);
        } else {
//This is interpreted as a file name
          String fileName = httpQueryString.replaceFirst("/", "");
          fileName = URLDecoder.decode(fileName, "UTF-8");
          if (new File(fileName).isFile()) {
            sendResponse(200, fileName, true);
          } else {
            QueryString qs = new QueryString("interval", "5000");
            qs.add("complete", "5");
            qs.add("incomplete", "10");
            sendResponse(200, qs.toString(), false);
          }
        }
      } else {
        sendResponse(200, "<b>The Requested resource not found ...."
                + "Usage: http://127.0.0.1:5000 or http://127.0.0.1:5000/</b>", false);
      }
    } catch (Exception e) {
      System.out.println(e);
    }
  }

  public void sendResponse(int statusCode, String responseString, boolean isFile) throws Exception {

    String statusLine = null;
    String serverdetails = "Server: Java HTTPServer";
    String contentLengthLine = null;
    String fileName = null;
    String contentTypeLine = "Content-Type: text/plain" + "\r\n";
    FileInputStream fin = null;

    if (statusCode == 200) {
      statusLine = "HTTP/1.1 200 OK" + "\r\n";
    } else {
      statusLine = "HTTP/1.1 404 Not Found" + "\r\n";
    }

    if (isFile) {
      fileName = responseString;
      fin = new FileInputStream(fileName);
      contentLengthLine = "Content-Length: "
              + Integer.toString(fin.available()) + "\r\n";
      if (!fileName.endsWith(".htm") && !fileName.endsWith(".html")) {
        contentTypeLine = "Content-Type: \r\n";
      }
    }

    contentLengthLine = "Content-Length: " + responseString.length()
            + "\r\n";


    outToClient.writeBytes(statusLine);
    outToClient.writeBytes(serverdetails);
    outToClient.writeBytes(contentTypeLine);
    outToClient.writeBytes(contentLengthLine);
    outToClient.writeBytes("Connection: close\r\n");
    outToClient.writeBytes("\r\n");

    if (isFile) {
      sendFile(fin, outToClient);
    } else {
      outToClient.writeBytes(responseString);
    }

    outToClient.close();
  }

  public void sendFile(FileInputStream fin, DataOutputStream out) throws Exception {
    byte[] buffer = new byte[1024];
    int bytesRead;

    while ((bytesRead = fin.read(buffer)) != -1) {
      out.write(buffer, 0, bytesRead);
    }
    fin.close();
  }

  public static void main(String args[]) throws Exception {

    ServerSocket Server = new ServerSocket(5000, 10, InetAddress.getByName("127.0.0.1"));
    System.out.println("TCPServer Waiting for client on port 5000");

    while (true) {
      Socket connected = Server.accept();
      (new Tracker(connected)).start();
    }
  }

  public Map<String, List<String>> getUrlParameters(String url) throws UnsupportedEncodingException {
    Map<String, List<String>> params = new HashMap<>();
    String[] urlParts = url.split("\\?");
    if (urlParts.length > 1) {
      String query = urlParts[1];
      for (String param : query.split("&")) {
        String pair[] = param.split("=");
        String key = URLDecoder.decode(pair[0], "UTF-8");
        String value = "";
        if (pair.length > 1) {
          value = URLDecoder.decode(pair[1], "UTF-8");
        }
        List<String> values = params.get(key);
        if (values == null) {
          values = new ArrayList<>();
          params.put(key, values);
        }
        values.add(value);
      }
    }
    return params;
  }
}
